home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1990: Night of the Living Disc / Night of the Living Disc.2mg / Dev.CD.5 / Tools / DTS.Samples / SC09Lister / Print.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-25  |  31.3 KB  |  861 lines  |  [B0] Apple IIgs Source Code (0x000A)

  1. /**********************************************************************
  2. *
  3. * lister print.c -- Version 3.0
  4. *
  5. * Developer Technical Support Apple II Sample Code
  6. *
  7. * Copyright (c)
  8. * Apple Computer, Inc.  1988-1990
  9. * All Rights Reserved.
  10. *
  11. * Written by Keith Rollin.
  12. *
  13. * This file contains the code which does the printing stuff.  This
  14. * code was taken nearly intact from the original lister sample
  15. * code by Keith Rollin.
  16. *
  17. **********************************************************************/
  18.  
  19. #include <types.h>
  20. #include <font.h>
  21. #include <intmath.h>
  22. #include <memory.h>
  23. #include <qdaux.h>
  24. #include <resources.h>
  25.  
  26. #include "lister.h"
  27.  
  28. static char     headerFooter[130];
  29. static char     builtHF[255];
  30. static char     time[20];       /* String to hold the time when printing. */
  31.  
  32. static unsigned int     pageNum, lineHeight, lineTop, maxLines, lineBottom;
  33. static char             PSMoveStr[] = " moveto\r";
  34. static char             PSShow1[] = " (";
  35. static char             PSShow2[] = ") show\r";
  36.  
  37. static char     NoMemAlertString[] = "32/Not enough memory to print the file!!!/^#0";
  38.  
  39. /**********************************************************************/
  40.  
  41. /* This routine handles the print record.  Handling it is delayed until
  42. ** it is needed.  This makes starting up the application a little
  43. ** faster.  The print driver isn't loaded until the user commits to
  44. ** needing it.  Therefore, since the driver isn't loaded at startup
  45. ** time, startup is a little faster.
  46. ** The print.prRec field is initially NULL.  If it is, then we don't
  47. ** have a print record yet.  If we don't, then make one.
  48. ** Once it is made, then do the appropriate function.
  49. ** Function 0:  PrStlDialog
  50. ** Function 1:  PrJobDialog
  51. */
  52.  
  53. unsigned int    prRecHandler(command)
  54. unsigned int    command;
  55. {
  56.     unsigned int    confirmFlag, postScript;
  57.     PrRec           **prRec, *prRecPtr;
  58.  
  59.     zapLocals();
  60.  
  61.     if (!(prRec = print.prRec)) {
  62.         prRec = (PrRecHndl)NewHandle((unsigned long)sizeof(PrRec), _ownerid, 0, 0L);
  63.         if (_toolErr) return(0);
  64.  
  65.         print.prRec = prRec;
  66.         PrDefault(prRec);
  67.  
  68.         prRecPtr = *prRec;
  69.         postScript = (prRecPtr->prInfo.iDev == 3);
  70.             /* postScript true if we are printing to a LaserWriter. */
  71.  
  72.         if (postScript) {
  73.             prRecPtr->prStl.wDev   |= 0x02;     /* bit 1 on:   LaserWriter landscape mode. */
  74.             prRecPtr->prStl.crWidth = 2;        /* crWidth=2   LaserWriter condensed mode. */
  75.         }
  76.         else {
  77.             prRecPtr->prStl.wDev &= 0xFFF9;     /* bit 1 off:  ImageWriter landscape mode. */
  78.         }                                       /* bit 2 off:  ImageWriter condensed mode. */
  79.  
  80.         PrValidate(prRec);      /* Do this due to the changes to the record. */
  81.     }
  82.  
  83.     switch (command) {
  84.         case 0:
  85.             confirmFlag = PrStlDialog(prRec);
  86.             break;
  87.         case 1:
  88.             confirmFlag = PrJobDialog(prRec);
  89.             break;
  90.     }
  91.  
  92.     return(confirmFlag);
  93. }
  94.  
  95. /**********************************************************************/
  96.  
  97. /* This routine gets the current #-of-columns text and converts it
  98. ** into an integer.  It then makes sure that it is between 1 & 4.
  99. */
  100.  
  101. unsigned int    getNumCols()
  102. {
  103.     char            colText[16];
  104.     unsigned int    col;
  105.  
  106.     zapLocals();
  107.  
  108.     fmdLEGetText(mainWindow, Columns, colText);
  109.         /* Get the #-columns text via a fakeModalDialog access call. */
  110.     col = atoi(colText + 1);
  111.         /* Convert text to integer. */
  112.  
  113.     if (!col) col++;        /* Bring the # of columns within range. */
  114.     if (col > 4) col = 4;
  115.  
  116.     return(col);
  117. }
  118.  
  119. /**********************************************************************/
  120.  
  121. /* Convert a column # to a coordinate for the left margin of that column. */
  122.  
  123. unsigned int    setMargin(col)
  124. unsigned int    col;
  125. {
  126.     return((print.myPage.h2 - print.myPage.h1) * col / getNumCols() + print.myPage.h1);
  127. }
  128.  
  129. /**********************************************************************/
  130.  
  131. /* This routine take the string that is stored in the headerFooter string
  132. ** buffers, and starts parsing it, starting at the character indexed by the
  133. ** variable 'src'.  It will read up until the ned of the string or the next
  134. ** '|', parsing embedded commands, and placing the resulting string into
  135. ** 'builtHF'.
  136. **
  137. ** Special substitutions ('@' marks embedded command):
  138. **      D:  replace with current date.
  139. **      T:  replace with current time.
  140. **      L:  replace with full path name.
  141. **      S:  replace with file name (short pathname).
  142. **      P:  replace with page number.
  143. */
  144.  
  145. unsigned int    getLineSegment(src)
  146. unsigned int    src;
  147. {
  148.     unsigned int    dest, i, max, sLen;
  149.     char            pageText[3], *cptr;
  150.  
  151.     zapLocals();
  152.  
  153.     dest = 0;
  154.     sLen = headerFooter[0];
  155.  
  156.     while ((headerFooter[src] != '|') && (src <= sLen)) {
  157.         if (headerFooter[src] == '@') {
  158.             src++;                              /* Skip over the '@'        */
  159.  
  160.             cptr = (*file.pathRef + 2);
  161.             max  = *(unsigned int *)(*file.pathRef + 2);
  162.             if (max > 127) max = 127;
  163.             cptr += 2;
  164.  
  165.             switch (headerFooter[src++]) {      /* skips over format code   */
  166.                 case 'd':
  167.                 case 'D':
  168.                     for (i = 0;i <= 7; builtHF[dest++] = (time[i++] & 0x7F));
  169.                     break;
  170.                 case 't':
  171.                 case 'T':
  172.                     max = ReadBParam(0x35) ? 16 : 19;
  173.                     for (i = 9; i <= max; builtHF[dest++] = (time[i++] & 0x7F));
  174.                     break;
  175.                 case 'l':
  176.                 case 'L':
  177.                     for (i = 0; i < max; builtHF[dest++] = cptr[i++]);
  178.                     break;
  179.                 case 's':
  180.                 case 'S':
  181.                     for (i = 0; i < max; builtHF[dest++] = cptr[i++]);
  182.                     break;
  183.                 case 'p':
  184.                 case 'P':
  185.                     Int2Dec(pageNum, pageText, 3, false);
  186.                     for (i=0; i<=2; builtHF[dest++] = pageText[i++]);
  187.                     break;
  188.                 default:
  189.                     src -= 2;       /* Go back to the '@' and copy it       */
  190.                     builtHF[dest++] = headerFooter[src++];
  191.                     /* end up pointing to ex-format code, and printing it   */
  192.                     break;
  193.             }  /* end switch */
  194.         } else {
  195.             builtHF[dest++] = headerFooter[src++];
  196.         }  /* == '@' */
  197.     }       /* == '|' */
  198.     builtHF[dest] = '\0'; /* replace the '|' with a NULL, ending the string */
  199.  
  200.     return(++src);      /* skip over the '|' */
  201. }
  202.  
  203. /**********************************************************************/
  204.  
  205. /* If we are printing in PostScript mode, we need to fix up the string.
  206. ** The characters "/", "(", and ")" are special to PostScript.  In order
  207. ** to print them, we need to stick a "\" in front of them.
  208. */
  209.  
  210. void    fixString(string)
  211. char    string[];
  212. {
  213.     char            *srcPtr, *destPtr;
  214.     char            ch;
  215.     static char     strCopy[255];
  216.  
  217.     zapLocals();
  218.  
  219.     srcPtr  = string;           /* Set up pointers to the source string and */
  220.     destPtr = strCopy;          /* to the buffer where a copy of it will go */
  221.  
  222.     while (*destPtr++ = *srcPtr++);     /* Make a copy of the string        */
  223.  
  224.     srcPtr  = strCopy;                  /* reset our pointers               */
  225.     destPtr = string;
  226.  
  227.     while (ch = *srcPtr++) {            /* Now fix all of the characters    */
  228.         if ((ch == '\\') || (ch == '(') || (ch == ')')) {
  229.             *destPtr++ = '\\';
  230.         }
  231.         if (ch != 0x0D) *destPtr++ = ch;    /* and remove carriage returns! */
  232.     }
  233.     *destPtr = '\0';                    /* make this thing a C String       */
  234. }
  235.  
  236. /**********************************************************************/
  237.  
  238. /* Sends the specified string out at the specified location.  This routine
  239. ** determines if we are in PostScript mode, and will create a PostScript
  240. ** command string if so.  If not, it will simply use QuickDraw to draw the
  241. ** string.
  242. */
  243.  
  244. void            sendString(line, x, y)
  245. char            line[];
  246. unsigned int    x, y;
  247. {
  248.     char            xStr[6], yStr[6];
  249.     static char     printStr[255];
  250.  
  251.     zapLocals();
  252.  
  253.     if (!line[0]) return;               /* Do nothing on a NULL string. */
  254.  
  255.     if (print.postScript) {
  256.         fixString(line);                /* Escape out all '\', '(', and ')'     */
  257.         Int2Dec(x, xStr, 5, true);      /* Put XY coordinates into ASCII        */
  258.         Int2Dec(y, yStr, 5, true);
  259.         xStr[5] = '\0';                 /* Int2Dec just returns the ASCII chars */
  260.         yStr[5] = '\0';                 /* We need to turn them into C Strings  */
  261.         strcpy(printStr, xStr);         /* Build a moveTo PostScript command    */
  262.         strcat(printStr, yStr);
  263.         strcat(printStr, PSMoveStr);
  264.         strcat(printStr, PSShow1);
  265.         strcat(printStr, line);         /* Catenate the string to print.        */
  266.         strcat(printStr, PSShow2);      /* Catenate a 'show' command.           */
  267.         DrawCString(printStr);          /* Send it to LaserWriter driver.       */
  268.     } else {
  269.         MoveTo(x, y);                   /* Use QuickDraw to position and        */
  270.         DrawCString(line);              /* display the string.                  */
  271.     }
  272. }
  273.  
  274. /**********************************************************************/
  275.  
  276. /* Takes a string assumed to be a header or footer, and prints it where
  277. ** it is told to.  This routine gets the current time, and then calls
  278. ** getLineSegment() to get part of the header/footer and parse out the
  279. ** special codes in it.  Then it calls sendString to print it out.  It
  280. ** this this 3 times for the 3 possible segments of the header/footer.
  281. */
  282.  
  283. void            drawHeaderFooter(v, left, right)
  284. unsigned int    v, left, right;
  285. {
  286.     unsigned int    src, width;
  287.  
  288.     zapLocals();
  289.  
  290.     ReadAsciiTime(time);                    /* Get the current time for parsing      */
  291.     src = 1;                                /* Start parsing the string at the start */
  292.     src = getLineSegment(src);              /* Get a parsed line segment.  Set src.  */
  293.     sendString(builtHF, left + 10, v);      /* Print it in the left slot             */
  294.  
  295.     src = getLineSegment(src);              /* Get another segment where we left off */
  296.     width = CStringWidth(builtHF);          /* Find width in order to center it      */
  297.     sendString(builtHF, (right + left - width) / 2, v);         /* Print it centered */
  298.  
  299.     getLineSegment(src);                    /* Get the last segment.                */
  300.     width = CStringWidth(builtHF);          /* Get width to right justify it        */
  301.     sendString(builtHF, right - 10 - width, v);                 /* and print it.    */
  302. }
  303.  
  304. /**********************************************************************/
  305.  
  306. /* Read the header string from the lineEdit control, and call upon
  307. ** drawHeaderFooter() to format it, position it, and print it.
  308. */
  309.  
  310. void            printHeader(column)
  311. unsigned int    column;
  312. {
  313.     unsigned int    row;
  314.  
  315.     zapLocals();
  316.  
  317.     fmdLEGetText(mainWindow, Header, headerFooter);
  318.     row = print.myPage.v1 + lineHeight + lineHeight / 2;
  319.     drawHeaderFooter(row, setMargin(column), setMargin(column + 1));
  320. }
  321.  
  322. /**********************************************************************/
  323.  
  324. /* Read the Footer string from the EditLine item, and call upon
  325. ** DrawHeaderFooter() to format it, position it, and print it.
  326. */
  327.  
  328. void            printFooter(column)
  329. unsigned int    column;
  330. {
  331.     unsigned int    row;
  332.  
  333.     zapLocals();
  334.  
  335.     fmdLEGetText(mainWindow, Footer, headerFooter);
  336.     row = print.myPage.v2 - lineHeight + lineHeight / 2;
  337.     drawHeaderFooter(row, setMargin(column), setMargin(column + 1));
  338. }
  339.  
  340. /**********************************************************************/
  341.  
  342. /* Draw any borders needed.  If the Global "Borders Needed" flag
  343. ** (print.myBorders[0].used) is FALSE, then do nothing.  Else, check the
  344. ** flags for each part of the borders array, and print the border line if
  345. **  appropriate.
  346. */
  347.  
  348. void    drawPageBorders()
  349. {
  350.     unsigned int    v1, v2, h1, h2, margin, column;
  351.  
  352.     zapLocals();
  353.  
  354.     v1 = print.myPage.v1;
  355.     h1 = print.myPage.h1;
  356.     v2 = print.myPage.v2;
  357.     h2 = print.myPage.h2;
  358.  
  359.     if (print.myBorders[0].used) {
  360.         if (print.myBorders[1].used) {
  361.             MoveTo(h1, v1);
  362.             LineTo(h2, v1);
  363.         }
  364.         if (print.myBorders[2].used) {
  365.             MoveTo(h1, v1 + lineHeight * 2);
  366.             LineTo(h2, v1 + lineHeight * 2);
  367.         }
  368.         if (print.myBorders[3].used) {
  369.             MoveTo(h1, v2 - lineHeight * 2);
  370.             LineTo(h2, v2 - lineHeight * 2);
  371.         }
  372.         if (print.myBorders[4].used) {
  373.             MoveTo(h1, v2);
  374.             LineTo(h2, v2);
  375.         }
  376.         if (print.myBorders[5].used) {
  377.             MoveTo(h1, v1);
  378.             LineTo(h1, v2);
  379.         }
  380.         if (print.myBorders[7].used) {
  381.             MoveTo(h2, v1);
  382.             LineTo(h2, v2);
  383.         }
  384.         if ((print.myBorders[6].used) && (getNumCols() > 1)) {
  385.             for (column = 1; column < getNumCols(); column++) {
  386.                 margin = setMargin(column);
  387.                 MoveTo(margin, v1);
  388.                 LineTo(margin, v2);
  389.             } /* end for */
  390.         } /* end if print.myBorders[6] etc. */
  391.     } /* end of "if any borders are used at all" */
  392. }
  393.  
  394. /**********************************************************************/
  395.  
  396. /* This function makes any necessary adjustments to the text, due to
  397. ** the format the text is in.  (Merlin has hi-bit on chars, for
  398. ** example.)
  399. */
  400.  
  401. void    adjustText(line)
  402. char    *line;
  403. {
  404.     unsigned int    orval, andval, c;
  405.  
  406.     zapLocals();
  407.  
  408.     switch(fmdWhichRadio(mainWindow, 1)) {
  409.         case 0:
  410.             orval  = 0x00;
  411.             andval = 0xFF;
  412.             break;
  413.         case 1:
  414.             orval  = 0x00;
  415.             andval = 0x7F;
  416.             break;
  417.         case 2:
  418.             orval  = 0x80;
  419.             andval = 0xFF;
  420.             break;
  421.     }
  422.  
  423.     for (;; line++) {
  424.         if (!(c = *line)) break;
  425.         *line = (c | orval) & andval;
  426.     }
  427. }
  428.  
  429. /**********************************************************************/
  430.  
  431. unsigned int    nextTabLoc(loc)
  432. unsigned int    loc;
  433. {
  434.     char            *cptr;
  435.     unsigned int    c, dt, oldt, t, temp;
  436.  
  437.     zapLocals();
  438.  
  439.     for (dt = oldt = t = 0, cptr = print.tabsData + 1;;) {
  440.  
  441.         temp = atoi(cptr) * CharWidth('0');     /* Representative character     */
  442.                                                 /* width for tabbing purposes.  */
  443.  
  444.         if (temp > t) {                 /* Make sure that we aren't going backwards. */
  445.             oldt = t;
  446.             t = temp;                   /* t is now bigger than oldt. */
  447.         }
  448.  
  449.         if (loc < t) return(t);         /* That was easy. */
  450.  
  451.         for (;; cptr++) if (((c = *cptr) == ',') || (c == 0xC9) || (!c)) break;
  452.                                         /* Move to next tab value. */
  453.  
  454.         if (!c) return(loc);            /* No more tabs.  Return location passed to us. */
  455.  
  456.         if (!*++cptr) break;            /* String ended with a comma or ellipses. */
  457.     }
  458.  
  459.     if (!(c = t - oldt)) return(loc);   /* Ignore the tab-'til op, since it is invalid. */
  460.  
  461.     for (;;) {                          /* Do the tab-'til thing, since it is valid. */
  462.         t += c;
  463.         if (loc < t) return(t);
  464.     }
  465. }
  466.  
  467. /**********************************************************************/
  468.  
  469. /* Print a single column.  It prints any headers and/or footers, and then
  470. ** loops through the number of lines printable on the page.  For every time
  471. ** through the loop, it reads a line from the file, and calls sendString
  472. ** to print it in thr right location and right mode (PostScript or Quick-
  473. ** Draw II).  If we reached the end of the file, return this fact to
  474. ** printAPage().
  475. */
  476.  
  477. unsigned int    printAColumn(column)
  478. unsigned int    column;
  479. {
  480.     WindowPtr       fwptr;
  481.     unsigned int    orval, andval, lineNum, margin, x, y, i, c, done;
  482.     char            *cptr;
  483.  
  484.     zapLocals();
  485.  
  486.     switch(fmdWhichRadio(mainWindow, 1)) {
  487.         case 0:
  488.             orval  = 0x00;
  489.             andval = 0xFF;
  490.             break;
  491.         case 1:
  492.             orval  = 0x00;
  493.             andval = 0x7F;
  494.             break;
  495.         case 2:
  496.             orval  = 0x80;
  497.             andval = 0xFF;
  498.             break;
  499.     }
  500.  
  501.     if (print.haveHeader) printHeader(column);
  502.     if (print.haveFooter) printFooter(column);
  503.  
  504.     lineNum = 1;
  505.     margin = setMargin(column);
  506.  
  507.     do {
  508.  
  509.         done = (!readFile(&file));
  510.         if (_fileErr) {
  511.             done = 1;                           /* If we have a file error, we are done. */
  512.             if (_fileErr != eofEncountered)     /* If the file error was not EOF, then   */
  513.                 fileErr();                      /* we have to report it.                 */
  514.         }
  515.  
  516.         if (!done) {
  517.  
  518.             if (print.tabChr == 160) {          /* Danger:  Merlin file. */
  519.                 if (line[0] == ';' + 128) {     /* DANGER:  Leading semi. */
  520.                     BlockMove(line, line + 3, (unsigned long)252);
  521.                     line[255] = 0;
  522.                     line[0] = line[1] = line[2] = 160;
  523.                 }
  524.             }       /* The leading semi now is at 3rd tab location, like Merlin says. */
  525.  
  526.             x = 0;
  527.             y = lineNum * lineHeight + lineTop;
  528.             cptr = line;
  529.  
  530.             for (i = 0;;) {
  531.                 c = cptr[i];                        /* See what we have. */
  532.                 if ((c == print.tabChr) || (!c)) {  /* Are we at a tab or EOL? */
  533.  
  534.                     cptr[i] = 0;                    /* Terminate this string segment. */
  535.                     sendString(cptr, x + margin + 10, y);   /* Print the segment. */
  536.                     if (!c) break;                  /* It was our last segment. */
  537.  
  538.                     x += CStringWidth(cptr);        /* Tab over for next line segment. */
  539.                     x = nextTabLoc(x);
  540.  
  541.                     cptr += i + 1;                  /* Prepare for the next segment. */
  542.                     i = 0;
  543.                 }
  544.                 else cptr[i++] = (c | orval) & andval;
  545.             }
  546.         }
  547.  
  548.     } while ((!done) && (lineNum++ < maxLines));
  549.  
  550.     return(done);
  551. }
  552.  
  553. /**********************************************************************/
  554.  
  555. /* Called by the heart of the print loop to print a single page.  This
  556. ** routine draws the borders, sets up the printer for PostScript input
  557. ** if it is a LaserWriter, prints number of columns, and then turns
  558. ** off PostScript mode if appropriate.  This routine also detects if
  559. ** we reached the end of the file or not, and sends that bit of information
  560. ** back to the print loop to tell it to stop when it's time.
  561. */
  562.  
  563. unsigned int    printAPage()
  564. {
  565.     unsigned int    column, prErrorSave;
  566.     unsigned int    done;
  567.  
  568.     zapLocals();
  569.  
  570.     column = 0;
  571.     MoveTo(20,20);                              /* Force a font to be set.      */
  572.     DrawChar(' ');
  573.     drawPageBorders();
  574.  
  575.     if (print.postScript) {
  576.         PicComment(PostScriptBegin,  0, NIL);   /* Turn on PostScripting        */
  577.         PicComment(TextIsPostScript, 0, NIL);   /* Set form of PostScripting    */
  578.     }
  579.  
  580.     do {                                        /* Print x number of columns    */
  581.         done = printAColumn(column);
  582.         column++;
  583.         pageNum++;
  584.     } while ((!done) && (column < getNumCols()));
  585.  
  586.     if (print.postScript) {
  587.  
  588.         /* If an error occurred, PrError() would cause all Print Manager    */
  589.         /* routines to short-circuit themselves.  If so, then we won't be   */
  590.         /* able to turn off PostScripting! So we have to save the current   */
  591.         /* value of PrError(), set it to zero, turn off PostScripting, and  */
  592.         /* then set PrError() back to its old value.  NOTE: This is only a  */
  593.         /* problem with System Disk 3.2; the Print Manager on System Disk   */
  594.         /* 4.0 clears PostScript mode on PrClosePage().                     */
  595.  
  596.         prErrorSave = PrError();
  597.         PrSetError(0);
  598.         PicComment(PostScriptEnd,0,NIL);    /* Turn off PostScripting.      */
  599.         PrSetError(prErrorSave);
  600.     }
  601.  
  602.     return(done);   /* Tell Print Loop if this was the Last Page or not.    */
  603. }
  604.  
  605. /**********************************************************************/
  606.  
  607. void            showError(err)
  608. unsigned int    err;
  609. {
  610.     char            *errStr;
  611.  
  612.     static char     PrintErrNum[] = "xxxx";
  613.     static char     *SubStrings[] = {PrintErrNum};
  614.  
  615.     zapLocals();
  616.  
  617.     if (err) {
  618.         switch(err) {
  619.             case prAbort:
  620.                 errStr = "32/Printing was canceled because you pressed \021-./^#0";
  621.                 break;
  622.             case missingDriver:
  623.                 errStr = "32/Specified driver not in the DRIVERS subdirectory of the SYSTEM subdirectory/^#0";
  624.                 break;
  625.             case portNotOn:
  626.                 errStr = "32/Specified port not selected in the Control Panel./^#0";
  627.                 break;
  628.             case noPrintRecord:
  629.                 errStr = "32/No print record was specified./^#0";
  630.                 break;
  631.             case badLaserPrep:
  632.                 errStr = "42/The version of the LaserPrep file in the LaserWriter is not compatible with this version of the Print Manager/^#0";
  633.                 break;
  634.             case badLPFile:
  635.                 errStr = "42/The version of the LaserPrep file in the DRIVERS subdirectory in the SYSTEM subdirectory is not compatible with this verson of the Print Manager/^#0";
  636.                 break;
  637.             case papConnNotOpen:
  638.                 errStr = "32/Connection couldn't be established with the LaserWriter./^#0";
  639.                 break;
  640.             case papReadWriteErr:
  641.                 errStr = "32/Read-Write error on the LaserWriter./^#0";
  642.                 break;
  643.             case 0x1308:
  644.                 errStr = "32/Connection to the printer failed./^#0";
  645.                 break;
  646.             default:
  647.                 errStr = NULL;
  648.         }
  649.         
  650.         if (errStr) AlertWindow(0, NULL, errStr);
  651.         else {
  652.             Int2Hex(PrError(), PrintErrNum, 4);
  653.             AlertWindow(0, SubStrings, "32/Print error $*0 occured!!!/^#0");
  654.         }
  655.     }
  656. }
  657.     
  658. /**********************************************************************/
  659.  
  660. /* Routine called in response to choosing Print from the menu.  It sets
  661. ** up some variables, and then goes into the Classic Print Loop:
  662. **
  663. **      Display Job Dialog box
  664. **      Open the Document
  665. **          Open the Page
  666. **              Install my font
  667. **              Print the Page
  668. **          Close the Page
  669. **      Until all pages are printed
  670. **      UnSpool the picture if Printing to an ImageWriter
  671. */
  672.  
  673. void    doPrint()
  674. {
  675.     WindowPtr       cancelPrintWindow;
  676.     GrafPortPtr     keepPort, prPort;
  677.     unsigned long   id;
  678.     PrRecPtr        prRecPtr;
  679.     FontInfoRecord  theInfoRec;
  680.     PrStatusRec     myStatusRec;
  681.     FontHndl        oldFont;
  682.     unsigned int    done, val, i, firstPage, lastPage;
  683.  
  684.     /* Get some last minute information, and give user a chance to Cancel   */
  685.  
  686.     zapLocals();
  687.  
  688.     print.myBorders[0].used = GetCtlValue(GetCtlHandleFromID(mainWindow, UseBorder));
  689.  
  690.     val = GetCtlValue(GetCtlHandleFromID(mainWindow, BoxProc));
  691.     for (i = 1; i <= 7; i++) {
  692.         print.myBorders[i].used = (val & 0x01);
  693.         val = val >> 1;
  694.     }
  695.  
  696.     if (prRecHandler(1)) {
  697.  
  698.         getTabsInfo();      /* The tabsWindow may be active, in which case,
  699.                             ** we don't have the latest info. */
  700.  
  701.         keepPort = GetPort();
  702.         cancelPrintWindow = NewWindow2(NULL, NULL, NULL, NULL, 2, NowPrintingID, rWindParam1);
  703.         if (_toolErr) cancelPrintWindow = NULL;
  704.         else {
  705.             BeginUpdate(cancelPrintWindow);         /* The Begin & End update get rid */
  706.             DrawControls(cancelPrintWindow);        /* of the update event.  This is  */
  707.             EndUpdate(cancelPrintWindow);           /* good.                          */
  708.         }
  709.  
  710.         prRecPtr = *print.prRec;        /* Dereference the print record. */
  711.                                         /* We need information.          */
  712.  
  713.         firstPage = prRecPtr->prJob.iFstPage;   /* Process # pages to print. */
  714.         lastPage  = prRecPtr->prJob.iLstPage;
  715.         if (!firstPage) firstPage = 1;
  716.         if (lastPage < firstPage) lastPage = firstPage;
  717.         firstPage = (--firstPage) / getNumCols() + 1;
  718.         lastPage  = (--lastPage)  / getNumCols() + 1;
  719.         prRecPtr->prJob.iFstPage = firstPage;
  720.         prRecPtr->prJob.iLstPage = lastPage;
  721.  
  722.  
  723.         print.postScript = (prRecPtr->prInfo.iDev == 3);
  724.             /* print.postScript true if we are printing to a LaserWriter. */
  725.  
  726.         print.sideways = prRecPtr->prStl.wDev & 0x02;
  727.         if (!print.postScript) print.sideways ^= 0x02;
  728.  
  729.         /* Set up our own logical page size.  This lets me set some margin  */
  730.         /* space for 3-hole punches.                                        */
  731.  
  732.         print.myPage.v1 = prRecPtr->prInfo.rPage.v1 + (print.sideways ? 50:5);
  733.         print.myPage.h1 = prRecPtr->prInfo.rPage.h1 + (print.sideways ? 5:50);
  734.         print.myPage.v2 = prRecPtr->prInfo.rPage.v2 - 5;
  735.         print.myPage.h2 = prRecPtr->prInfo.rPage.h2 - 5;
  736.             /* print.myPage will be used for page calculations. */
  737.  
  738.         oldFont = GetFont();
  739.         InstallFont(print.theFont.fidLong, 0);  /* Do this once so we can get info on it. */
  740.         GetFontInfo(&theInfoRec);
  741.         SetFont(oldFont);                       /* Set us back to the System Font. */
  742.  
  743.         lineHeight = theInfoRec.ascent + theInfoRec.descent + theInfoRec.leading;
  744.  
  745.         pageNum = 1;        /* Initialize the page number counters. */
  746.  
  747.  
  748.         /* Set up variables used to determine where to start and stop       */
  749.         /* printing on the page.                                            */
  750.         /*                                                                  */
  751.         /* Step One: assume that there are no borders, headers, or          */
  752.         /* footers.                                                         */
  753.  
  754.         lineTop    = print.myPage.v1;
  755.         lineBottom = print.myPage.v2;
  756.  
  757.         /* Step Two: See what types of borders we are using, and            */
  758.         /* adjust the top and bottom margins accordingly.                   */
  759.  
  760.         if (print.myBorders[0].used) {
  761.             if (print.myBorders[1].used) lineTop = print.myPage.v1 + lineHeight;
  762.             if (print.myBorders[2].used) lineTop = print.myPage.v1 + lineHeight * 3;
  763.             if (print.myBorders[4].used) lineBottom = print.myPage.v2 - lineHeight;
  764.             if (print.myBorders[3].used) lineBottom = print.myPage.v2 - lineHeight * 3;
  765.         }
  766.  
  767.         /* Step Three: Get the header and footer text.  If there is any,    */
  768.         /* then set aside space for them.                                   */
  769.  
  770.         fmdLEGetText(mainWindow, Header, headerFooter);
  771.         print.haveHeader = *headerFooter;
  772.         fmdLEGetText(mainWindow, Footer, headerFooter);
  773.         print.haveFooter = *headerFooter;
  774.  
  775.         if (print.haveHeader) lineTop    = print.myPage.v1 + lineHeight * 3;
  776.         if (print.haveFooter) lineBottom = print.myPage.v2 - lineHeight * 3;
  777.  
  778.  
  779.         /* Figure out how many lines that comes out to.                     */
  780.         maxLines = (lineBottom - lineTop) / lineHeight;
  781.  
  782.         /* Attempt to open the file.  If that succeeds, then go into the    */
  783.         /* printing loop.                                                   */
  784.  
  785.         if (!openFile(&file)) {     /* If file opened without incident...   */
  786.  
  787.             /* We now enter into the Classical Print Loop.  Notice the       */
  788.             /* gyrations I go through in the middle with the checking of     */
  789.             /* PrError().  Normally, you wouldn't think that this would be   */
  790.             /* necessary, as the Print Manager will automatically skip over  */
  791.             /* the rest of the printing if an error occurs.  However, I have */
  792.             /* to make my routine more intelligent for 2 reasons:            */
  793.             /*      1) I can abort the reading of the rest of the file if    */
  794.             /*          I know that an error has occured.  Even though the   */
  795.             /*          Print manager won't print anything if an error       */
  796.             /*          occurs, I can speed things up by doing this.         */
  797.             /*      2) The Print Manager short-circuits all of its routines  */
  798.             /*          when an error occurs.  It makes a check of PrError() */
  799.             /*          at the beginning of all routines and if it is not    */
  800.             /*          equal to zero, it returns before doing anything      */
  801.             /*          else.  However, assume the case where the user       */
  802.             /*          presses Cmd-. before PrOpenPage() is called for the  */
  803.             /*          time.  Among other things, PrOpenPage() is respon-   */
  804.             /*          sible for setting the port to the Printer Port       */
  805.             /*          ('prPort' as listed below).  If Cmd-. is pressed,    */
  806.             /*          PrOpenPage() will not do that, and the port is left  */
  807.             /*          set to my Dialog Window.  If I were to then perform  */
  808.             /*          my InstallFont(), I would set the font of the        */
  809.             /*          Dialog Window, and not the Printer Port, like I      */
  810.             /*          wanted.  So I have to make a check of PrError to see */
  811.             /*          if it is OK to proceed.                              */
  812.  
  813.             prPort = PrOpenDoc(print.prRec, NULL);  /* Start a print session    */
  814.             if (_toolErr) PrSetError(_toolErr);
  815.  
  816.             do {
  817.                 PrOpenPage(prPort, NULL);   /* Open port for printing into. */
  818.                 if (_toolErr) PrSetError(_toolErr);
  819.                 if (PrError()) {                            /* If an error occurs... */
  820.                     done = TRUE;                            /* ... get outta here!   */
  821.                 } else {                                    /* If no error occurs... */
  822.                     InstallFont(print.theFont.fidLong, 0);  /* ...reset the font...  */
  823.                     done = printAPage();                    /* ...and print a page.  */
  824.                 }
  825.                 PrClosePage(prPort);            /* Close the printer's GrafPort */
  826.                 if (_toolErr) PrSetError(_toolErr);
  827.             } while (!done);                    /* "Bop 'til you drop!"         */
  828.  
  829.             PrCloseDoc(prPort);                 /* Close this print session.    */
  830.             if (_toolErr) PrSetError(_toolErr);
  831.  
  832.             closeFile(&file);                   /* Close the file.              */
  833.             fileErr();
  834.  
  835.             if (!PrError()) {                   /* If no error occured...       */
  836.                 if (MaxBlock() < 10240) {       /* Enough memory to de-spool?   */
  837.                     PurgeAll(_ownerid);         /* No - try to get some.        */
  838.                     CompactMem();
  839.                     if (MaxBlock() < 10240)     /* Enough memory now?           */
  840.  
  841.                         /* Not enough memory to de-spool to the ImageWriter */
  842.                         /* so show a dialog box saying so.  However, that   */
  843.                         /* begs the question of whether or not we have      */
  844.                         /* enough memory to show this dialog box...         */
  845.  
  846.                         AlertWindow(0, NULL, NoMemAlertString);
  847.                         SetPort(keepPort);
  848.                         return;
  849.                 };
  850.                 PrPicFile(print.prRec, NULL, &myStatusRec);
  851.  
  852.             } else showError(PrError());
  853.         }
  854.         else fileErr();                     /* The file never even opened. */
  855.  
  856.         SetPort(keepPort);
  857.         CloseWindow(cancelPrintWindow);     /* Remove status box.   */
  858.         cancelPrintWindow = NULL;
  859.     }
  860. }
  861.